# -*- coding: UTF-8 -*-
#-------------------------------------------------------------------------------
# Name:        persistences.py
# Purpose:
#
# Author:      Drago@
#
# Created:     06.08.2009
# Copyright:   (c) Drago@ 2009
# Licence:     <your licence>
#-------------------------------------------------------------------------------
#!/usr/bin/env python

# TODO Check all input params on injection!

import Pyro.core
from hashlib import sha1, md5
from random import random

from pygs.interfaces import IPersistenceInterface, BaseService
from pygs.data import Point
from pygs.logger import logger

import pygs.helpers as helpers

import MySQLdb

class MySQLPersistence(BaseService, Pyro.core.ObjBase, IPersistenceInterface):
    """
        MySQL DB persistence implementation
    """

    con = None
    encoderSHA1 = sha1()
    encoderMD5 = md5()

    def __init__(self):
        Pyro.core.ObjBase.__init__(self)

    def startup(self, params = None):
        BaseService.startup(self, params)
        assert params or self.params, 'Must define params for startup service!'
        if params:
            self.params = params
        # open connection to DB with params
        host = self.params["host"]
        port = self.params["port"]
        user = self.params["user"]
        passwd = self.params["passwd"]
        db = self.params["db"]
        self.con = MySQLdb.connect(host=host, port=port, user=user, passwd=passwd, db=db)
        self.con.autocommit(1)
        logger.log("Connection to MySQL established. Host = '%s', port = '%s', user = '%s'." %
            (host, port, user))

    def shutdown(self):
        BaseService.shutdown(self)
        self.con.close()
        logger.log("Connection to MySQL closed.")

    def addPoints(self, points):
        # write data
        for point in points:
            logger.log("Saving %s..." % point)

            try:
                self.con.query("CALL `pygs`.`AddPoint`(%s, %s, %s, %s, %s, %s);" %
                    (point.latitude, point.longitude, point.altitude,
                     helpers.ISO8601TimeToMySQL(point.time),
                     point.pointTypeId, point.trekingObjectId))
                logger.log("Saved %s." % point)
##                self.con.commit()
            except:
##                self.con.rollback()
                raise

    def getPoints(self, token, trekingObjectId, dateFrom, dateTo):
        # get points
        cursor = self.con.cursor()
        query = ("CALL `pygs`.`GetPoints`('%s', %s, %s, %s);" %
            (token, trekingObjectId, helpers.ISO8601TimeToMySQL(dateFrom), helpers.ISO8601TimeToMySQL(dateTo)))
        logger.debug("Get points query: \n%s" % query)
        cursor.execute(query)
        pointsInfo = [] 
        # Fetch data from cursor
        results = cursor.fetchall()
        for row in results:
            pointsInfo.append(Point(row[0], row[1], row[2], row[3], row[4], trekingObjectId))
            
        return pointsInfo
                
    # TODO: Maybe need to create separate security persistence?
    def getToken(self, userName, passwd, expirationDate):
        # get user ID
        cursor = self.con.cursor()
        query = ("SELECT `pygs`.`GetUserIDByNameAndPass`('%s', '%s');" %
            (userName, passwd))
        logger.debug("Find user query: \n%s" % query)
        cursor.execute(query)
        result = cursor.fetchone()
        faultMessage = "User '%s' is not found or password is incorrect." % userName
        if not result[0]:
            logger.log(faultMessage)
            raise Exception(faultMessage)

        # if user exists, create session and return token
        userID = result[0]
        newToken = self.generateNewToken()

        try:
            query = r"""
                /* TODO: Check for previous session. Delete or use previous unexpired session? */

                /* Create session for user*/
                CALL `pygs`.`GetUserToken`(%s, '%s', '%s')
                """ % (userID, newToken, expirationDate)
            logger.debug("New token query: \n%s" % query)
            self.con.query(query)
##            self.con.commit()
        except:
##            self.con.rollback()
            raise
        return newToken

    def deleteToken(self, token):
        # get user ID
        cursor = self.con.cursor()
        query = "SELECT  `pygs`.`GetUserIDByToken`('%s');" % token
        logger.debug("Get user by token query: \n%s" % query)
        cursor.execute(query)
        result = cursor.fetchone()
        if not result[0]:
            logger.log("User by token '%s' not found!" % token)
            return False

        # if user exists, create session and return token
        userID = result[0]

        try:
            query = "CALL `pygs`.`DeleteUserSessionByToken`(%s, '%s');" % (userID, token)
            logger.debug("Delete token query: \n%s" % query)
            self.con.query(query)
##            self.con.commit()
            return True
        except:
##            self.con.rollback()
            raise

    def hasRight(self, token, rightType):
        try:
            # get check result
            cursor = self.con.cursor()
            query = r"""SELECT `pygs`.`IsUserHasRight`('%s', '%s');""" % (token, rightType)
            logger.debug("Check rights with query:\n %s" % query)
            cursor.execute(query)
            result = cursor.fetchone()
            if not result:
                return False    
            # if result obtained return it
            return result[0]
        except:
            raise

    def isSessionExpired(self, token):
        try:
            # get check result
            cursor = self.con.cursor()
            query = r"""SELECT `pygs`.`IsSessionExpired`('%s');""" % (token)
            logger.debug("Check session expiration with query:\n %s" % query)
            cursor.execute(query)
            result = cursor.fetchone()
            if not result:
                return True    
            # if result obtained return it
            return result[0]
        except:
            raise

    def encodeSHA1(self, strToEncode):
        self.encoderSHA1.update(strToEncode)
        return self.encoderSHA1.hexdigest()

    def encodeMD5(self, strToEncode):
        self.encoderMD5.update(strToEncode)
        return self.encoderMD5.hexdigest()

    def generateNewToken(self):
        return self.encodeMD5(str(random()))
        
